# !/usr/bin/env python
# -*- coding: utf-8 -*-
"""
 -------------------------------------------------
    File Name:     __init__.py
    Description:   
 -------------------------------------------------
 """
import logging
import os
import pkgutil
import sys
from importlib import import_module
from pathlib import Path

from apitesting.core.base import BaseCommand

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def find_commands(management_dir) -> list:
    """
    给定管理目录的路径，返回所有可用的命令名称的列表。.

    :param management_dir: 管理目录的路径
    :return: 命令名称列表
    """
    command_dir = os.path.join(management_dir, "commands")
    command_list: list = [
        name
        for _, name, is_pkg in pkgutil.iter_modules([command_dir])  # 遍历命令目录下的所有模块
        if not is_pkg and not name.startswith("_")  # 排除以 _ 开头的文件夹
    ]
    return command_list


def load_command_class(app_name, name):
    """
    给定命令名称和应用程序名称，返回 Command 类实例。允许导入过程引发的所有错误(ImportError、AttributeError) 传播。
    """
    logger.info(f"Loading command '{name}' from '{app_name}'")
    module = import_module("%s.management.commands.%s" % (app_name, name))
    return module.Command()


def get_commands() -> dict:
    """
    返回将命令名称映射到其回调应用程序的字典。

    在 apitesting.core 中查找 management.commands 包，并在每个已安装的应用程序中查找 - 如果存在命令包，则注册该包中的所有命令。

    始终包含核心命令。如果已指定设置模块，则还包括用户定义的命令。

    字典的格式为 {command_name: app_name}。然后可以在对 load_command_class(app_name, command_name) 的调用中使用此字典中的键值对。

    字典在第一次调用时缓存，并在后续调用中重复使用。
    """
    commands: dict = {name: "apitesting.core" for name in find_commands(Path(__file__).parent.as_posix())}

    # if not settings.configured:
    #     return commands

    # for app_config in reversed(apps.get_app_configs()):
    #     path = os.path.join(app_config.path, "management")
    #     commands.update({name: app_config.name for name in find_commands(path)})

    return commands


class ManagementUtility:
    """
    Encapsulate the logic of the django-admin and manage.py utilities.
    """

    def __init__(self, argv=None):
        self.argv = argv or sys.argv[:]
        self.prog_name = os.path.basename(self.argv[0])  # 获取程序名称 manage.py
        if self.prog_name == "__main__.py":
            self.prog_name = "python -m django"
        self.settings_exception = None

    @staticmethod
    def fetch_command(subcommand):
        """
        尝试获取给定的子命令，如果找不到，则使用从命令行调用的适当命令（通常是“django-admin”或“manage.py”）打印一条消息。
        """
        # 获取 try 块之外的命令以防止吞噬异常
        commands: dict[str, str] = get_commands()

        try:
            app_name: str = commands[subcommand]
        except KeyError:
            print(f"Unknown command: {subcommand}")
            sys.exit(1)

        if isinstance(app_name, BaseCommand):
            # 如果命令已经加载，则直接使用
            klass = app_name
        else:
            klass = load_command_class(app_name, subcommand)
        return klass

    def execute(self):
        """
        根据命令行参数，确定正在运行哪个子命令，创建适合该命令的解析器，然后运行它.
        """
        try:
            subcommand = self.argv[1]
        except IndexError:
            subcommand = "help"  # 如果没有给出参数则显示帮助。

        # 运行子命令
        self.fetch_command(subcommand).run_from_argv(self.argv)


def execute_from_command_line(argv=None):
    """Run a ManagementUtility."""
    utility = ManagementUtility(argv)
    utility.execute()


if __name__ == '__main__':
    execute_from_command_line(argv=["manage.py", 'tree', 'apitesting'])